var CClosetModelTool = function (invalidateFun) {
    var that = this;
    this.invalidateFun = function () {
        //对于缩略图，直接在加载结束后将结果发送出去
        if (that.ignoretexture == true) {
            that.asynLoadedFile = that.asynLoadedFile - 1;
            if (that.asynLoadedFile == 0) {
                that.loadedCalback && that.loadedCalback(that.root);
            }
        }
        invalidateFun();
    };
};

CClosetModelTool.prototype.Create3DNode = function (data, funcGetResourceData, ignoretexture, loadedCalback) {
    var that = this;
    that.funcGetResourceData = funcGetResourceData;

    this.ignoretexture = ignoretexture;

    var root = new THREE.Object3D;
    root.userData.hgCloset = {};
    root.userData.hgCloset.guid = data.MemData.guid;
    root.userData.hgCloset.product = true;
    if (data.Product && data.Product.Drop && data.Product.Drop.drop == '拆解') {
        root.userData.hgCloset.dropToatal = false;
    }

    if (ignoretexture == true) {
        this.whiteBlackMat = new THREE.MeshBasicMaterial({ specular: 0xFFFFFF, shininess: 0 });
        this.whiteBlackMat.polygonOffset = true;
        this.whiteBlackMat.polygonOffsetFactor = 2;
        this.whiteBlackMat.side = THREE.DoubleSide;
        this.whiteBlackMat.userData.hgMatInfo = {};
        this.whiteBlackMat.userData.hgMatInfo.whiteBlackMat = true;

        this.asynLoadedFile = 0;    //需要异步加载的文件数量

        this.root = root;
        this.loadedCalback = loadedCalback;
    }

    //增加一个用于模块拖拽的参考模型，默认的时候是隐藏的
    var boxGeom = that._CreateBoxGeometry(data, new THREE.MeshPhongMaterial({ color: 0xff0000, opacity: 0.01, transparent: 1 }), true);
    boxGeom.name = "PickAssistBox";
    root.add(boxGeom);

    var product = data["Product"] || {};

    var blocks = product["BlockList"] || [];

    that.matContainer = {};
    that._CollectAllMaterial(data, that.matContainer);

    //异步把纹理加载上来
    for (var item in that.matContainer) {
        that._GetMaterial(that.matContainer[item]);
    }

    //创建图元
    for (var i = 0; i < blocks.length; ++i) {
        var node = that._Create3DNode(blocks[i]);
        if (!node) continue;
        blocks[i].Pos.OZ && node && node.rotateY(THREE.Math.degToRad(blocks[i].Pos.OZ));
        this._CreateLabelObj(blocks[i], root);
        node && root.add(node);
    }

    if (data.hasOwnProperty('Pos') && data.hasOwnProperty('Size') && !data.hasOwnProperty('Product')) {
        var blockNode = that._CreateRenderable(data);
        if (blockNode && blockNode.children.length > 0) {
            data.Pos.OZ && blockNode && blockNode.rotateY(THREE.Math.degToRad(data.Pos.OZ));
            blockNode && root.add(blockNode);
        }
    }
    if (data.MemData.Pos) {
        var pos = data.MemData.Pos;
        root.position.set(pos.X, pos.Y, pos.Z);
    }

    if (this.asynLoadedFile == 0) {
        this.loadedCalback && this.loadedCalback(this.root);
    }
    return root;
};

CClosetModelTool.prototype.Update3DNode = function (blockObj, parentNode) {

    this._CollectAllMaterial(blockObj, this.matContainer);
    //异步把纹理加载上来
    for (var item in this.matContainer) {
        this._GetMaterial(this.matContainer[item]);
    }

    var node = this._Create3DNode(blockObj);
    blockObj.Pos && blockObj.Pos.OZ && node && node.rotateY(THREE.Math.degToRad(blockObj.Pos.OZ));
    node && parentNode.add(node);

    if (parentNode && parentNode.userData.hgCloset == 'ProductsRoot') {
        //增加一个用于模块拖拽的参考模型，默认的时候是隐藏的
        var boxGeom = this._CreateBoxGeometry(blockObj, new THREE.MeshPhongMaterial({ color: 0xff0000, opacity: 0.01, transparent: 1 }), true);
        boxGeom.name = "PickAssistBox";
        node.add(boxGeom);
    }
    return node;
}

CClosetModelTool.prototype._CollectAllMaterial = function (blockObj, container) {
    if (blockObj.hasOwnProperty('Material')) {
        var mat = blockObj['Material'];
        var key = this._GetMatKey(mat);
        key.length > 0 && (container[key] == undefined) && (container[key] = mat);
    }
    if (blockObj.hasOwnProperty("Product")) {
        var product = blockObj["Product"];
        if (product.hasOwnProperty('Material')) {
            var mat = product['Material'];
            var key = this._GetMatKey(mat);
            key.length > 0 && (container[key] == undefined) && (container[key] = mat);
        }
        var blocks = product["BlockList"] || [];
        for (var i = 0; i < blocks.length; ++i) {
            this._CollectAllMaterial(blocks[i], container);
        }
    }
}

CClosetModelTool.prototype._Create3DNode = function (blockObj) {
    if (!blockObj || blockObj["DisplayType"] == 3)
        return undefined;

    var size = blockObj.MemData.Size;
    if (!size.L || !size.D || !size.H)
        return;

    var blockNode = new THREE.Object3D;
    blockNode.userData.hgCloset = {};
    blockNode.userData.hgCloset.guid = blockObj.MemData.guid;
    if (blockObj.SubSpace && blockObj.SubSpace.length > 0)
        blockNode.userData.hgCloset.spaceNode = true;
    var pos = blockObj.MemData.Pos;
    blockNode.position.set(pos.X, pos.Y, pos.Z);

    var size = blockObj.MemData.Size;
    if (blockObj.hasOwnProperty("Product")) {
        var product = blockObj["Product"];
        var blocks = product["BlockList"] || [];
        for (var i = 0; i < blocks.length; ++i) {
            var node = this._Create3DNode(blocks[i]);
            if (!node)
                continue;
            blocks[i].Pos && blocks[i].Pos.OZ && node && node.rotateY(THREE.Math.degToRad(blocks[i].Pos.OZ));
            this._CreateLabelObj(blocks[i], blockNode);
            node && blockNode.add(node);
        }
        if (blocks.length > 0) {
            blockNode.userData.hgCloset.product = true;
        }
    }
    if (blockObj.hasOwnProperty("ThreedGraphic")) {
        if (blockObj["ThreedGraphic"].indexOf('.3dlst') != -1) {
            this._CreateX3dRGeometryLst(blockObj, function (x3dNode) {
                if (x3dNode) {
                    blockNode.add(x3dNode);
                }
            })
        }
        else if (blockObj["ThreedGraphic"].indexOf('.path3d') != -1) {
            var pathUrl = blockObj["ThreedGraphic"];//this.funcGetX3d(blockObj["ThreedGraphic"]);
            this._CreatePath3dGeometry(blockObj, pathUrl, function (pathNode) {
                if (pathNode) {
                    blockNode.add(pathNode);
                }
            })
        }
        else {
            var x3dUrl = blockObj["ThreedGraphic"];//this.funcGetX3d(blockObj["ThreedGraphic"]);
            this._CreateX3dRGeometry(blockObj, x3dUrl, function (x3dNode) {
                if (x3dNode) {
                    blockNode.add(x3dNode);
                }
            });
        }

        //blockNode.add(this._createBoxGeometry(blockObj, express, size.L * 0.001, size.H * 0.001, size.D * 0.001,
        //    new THREE.LineBasicMaterial({ color: 0xff0000 }), true));
    }
    if (blockObj.hasOwnProperty("BasicGraphic")) {
        var node = this._CreateRenderable(blockObj);
        node && blockNode.add(node);
    }
    if (blockObj.SubSpace && blockObj.SubSpace.length > 0) {
        var spaceNode = this._CreateBoxGeometry(blockObj, new THREE.MeshPhongMaterial({ color: 0xff0000, opacity: 0.01, transparent: 1, side: THREE.DoubleSide }), true);
        spaceNode.userData.hgCloset = spaceNode.userData.hgCloset || {};
        spaceNode.userData.hgCloset.spaceNode = true;
        blockNode.add(spaceNode);
    }

    var vp = blockObj["VPType"] || 0;
    if (vp == 1) {//俯视
        blockNode.rotateX(THREE.Math.degToRad(-90));
        blockNode.position.z += size.H;
    }
    else if (vp == 2) {//左侧(B面)
        blockNode.rotateY(THREE.Math.degToRad(90));
        blockNode.position.z += size.L;
    }
    else if (vp == 3) {//右侧(C面)
        blockNode.rotateY(THREE.Math.degToRad(-90));
        blockNode.position.x += size.L;
    }
    else if (vp == 4) {//仰视
        blockNode.rotateX(THREE.Math.degToRad(90));
    }
    else if (vp == 5) {//反向
        blockNode.rotateY(THREE.Math.degToRad(180));
        blockNode.position.x += size.L;
        blockNode.position.z += size.D;
    }

    return blockNode;
};

CClosetModelTool.prototype._CreateRenderable = function (geoObj) {
    if (geoObj["NodeName"] == '变量' || geoObj["DisplayType"] == 3 || geoObj["BasicGraphic"] == "BG::NULL" || geoObj["BasicGraphic"] == "")
        return undefined;

    var node = new THREE.Object3D;
    var hasGraphic = false;
    if (geoObj["BasicGraphic"] && geoObj["BasicGraphic"].indexOf("::") == -1 && geoObj["BasicGraphic"] != 'BG_FRAMERECT') {
        var x2dUrl = geoObj["BasicGraphic"];//this.funcGetX2d(geoObj["BasicGraphic"]);
        var boxNode = this._CreateX2dRGeometry(geoObj, x2dUrl + ".x2d", function (nodeX2d) {
            console.log(nodeX2d)
            nodeX2d && node.add(nodeX2d);
        });
        
        boxNode && node.add(boxNode);
        hasGraphic = true;
    }

    if (geoObj["ThreedGraphic"] && geoObj["ThreedGraphic"] != "") {
        if (geoObj["ThreedGraphic"].indexOf('.3dlst') != -1) {
            var boxNode = this._CreateX3dRGeometryLst(geoObj, function (x3dNode) {
                x3dNode && node.add(x3dNode);
            });
            boxNode && node.add(boxNode);
        }
        else if (geoObj["ThreedGraphic"].indexOf('.path3d') != -1) {
            var pathUrl = geoObj["ThreedGraphic"];//this.funcGetX3d(geoObj["ThreedGraphic"]);
            this._CreatePath3dGeometry(geoObj, pathUrl, function (pathNode) {
                if (pathNode) {
                    node.add(pathNode);
                }
            })
        }
        else {
            var x3dUrl = geoObj["ThreedGraphic"];//this.funcGetX3d(geoObj["ThreedGraphic"]);
            var boxNode = this._CreateX3dRGeometry(geoObj, x3dUrl, function (x3dNode) {
                x3dNode && node.add(x3dNode);
            });
            boxNode && node.add(boxNode);
        }
        hasGraphic = true;
    }

    if (!hasGraphic) {
        var size = geoObj.MemData.Size;
        var expressGraph = new hg3dExpress(size, 1);
        expressGraph.setArgs({});
        var profileNode = this._CreateProfileGeomrtry(geoObj, expressGraph, size.L, size.H, size.D);
        var angle = geoObj.MemData.Params['CA'] || 0;
        if (angle != 0 && geoObj['GraphParam']) {
            var rotateDir = geoObj['GraphParam']['JX'];
            if (rotateDir == 3)//X旋转
                node.rotateX(THREE.Math.degToRad(angle));
            else if (rotateDir == 4)//Y旋转
                node.rotateZ(THREE.Math.degToRad(angle));
        }
        profileNode && node.add(profileNode);
    }

    return node;
}

CClosetModelTool.prototype._CreateX2dRGeometry = function (geoObj, x2dUrl, success) {
    
    var params = geoObj.MemData.Params;
    var that = this;
    var size = geoObj.MemData.Size;
    var L = size.L;
    var D = size.D;
    var H = size.H;
    this.ignoretexture && this.asynLoadedFile++;
    that.funcGetResourceData.apply(gMainApp, ['X2D', x2dUrl, function (responseText) {
        var root = new THREE.Object3D;

        var xmlParser = new DOMParser();
        var xmlData = xmlParser.parseFromString(responseText, "text/xml");

        var graph = xmlData.firstChild;
        var attribute = graph.attributes;
        var arg = {};
        for (var i = 0; i < attribute.length; ++i) {
            var key = attribute[i].nodeName;
            if (params.hasOwnProperty(key)) {
                arg[key] = { "值": params[key] };
            }
            else {
                if (key == 'CA' || key == 'CB' || key == 'CC' || key == 'CD' || key == 'CE' || key == 'CF' || key == 'CG' || key == 'CH' || key == 'CI' ||
                    key == 'CJ' || key == 'CK' || key == 'CL' || key == 'CM' || key == 'CN' || key == 'CO' || key == 'CP' || key == 'CQ') {
                    arg[key] = { "值": 0 };
                }
                else
                    arg[key] = { "值": attribute[i].nodeValue };
            }
        }

        for (var item in params) {
            arg[item] = { "值": params[item] };
        }

        arg["CA"] = arg["CA"] || { "值": 0 };
        arg["CB"] = arg["CB"] || { "值": 0 };
        arg["CC"] = arg["CC"] || { "值": 0 };
        arg["CD"] = arg["CD"] || { "值": 0 };
        arg["CE"] = arg["CE"] || { "值": 0 };
        arg["CF"] = arg["CF"] || { "值": 0 };
        arg["CG"] = arg["CG"] || { "值": 0 };
        arg["CH"] = arg["CH"] || { "值": 0 };
        arg["CI"] = arg["CI"] || { "值": 0 };
        arg["CJ"] = arg["CJ"] || { "值": 0 };
        arg["CK"] = arg["CK"] || { "值": 0 };
        arg["CL"] = arg["CL"] || { "值": 0 };
        arg["CM"] = arg["CM"] || { "值": 0 };
        arg["CN"] = arg["CN"] || { "值": 0 };
        arg["CO"] = arg["CO"] || { "值": 0 };
        arg["CP"] = arg["CP"] || { "值": 0 };
        arg["CQ"] = arg["CQ"] || { "值": 0 };

        //处理百叶
        if (arg.hasOwnProperty('Param')) {
            var x2dParam = arg['Param']["值"].replace(/\^/g, '\'');
            x2dParam = x2dParam.substr(1, x2dParam.length - 2);
            var paramsArray = x2dParam.split(',');
            var paramObj = {};
            for (var i = 0; i < paramsArray.length; ++i) {
                var keyvalue = paramsArray[i].split(':');
                if (keyvalue[0] == undefined || keyvalue[1] == undefined)
                    continue;
                keyvalue[0] = keyvalue[0].replace(/\'/g, '');
                keyvalue[1] = keyvalue[1].replace(/\'/g, '');
                paramObj[keyvalue[0]] = keyvalue[1];
            }
            geoObj.GraphParam = geoObj.GraphParam || paramObj;
        }
        var expressGraph = new hg3dExpress(arg, 1);

        var rootNode = new THREE.Object3D;
        var graphChildren = graph.children;
        var graphparam = geoObj.GraphParam || {};
        var graphNum = 1;
        if (graphparam.PL == 1 || graphparam.PL == 2 || graphparam.PL == 3) {
            if (graphparam.PL == 1) {//PlaneXY
                if (graphparam.BarH > 0 && graphparam.DJ != 0) {
                    if (graphparam.DJ == 1) {
                        graphparam.BarH = L / Math.round(L / graphparam.BarH);
                        graphNum = L / graphparam.BarH;
                        L = graphparam.BarH;
                    }
                    else if (graphparam.DJ == 2) {
                        graphparam.BarH = D / Math.round(D / graphparam.BarH);
                        graphNum = D / graphparam.BarH;
                        D = graphparam.BarH;
                    }
                }
                for (var i = 0; i < graphChildren.length; ++i) {
                    var element = graphChildren[i];
                    if (element.nodeName == "PlaneXY") {
                        expressGraph.L = L;
                        arg["W"] = { "值": D };
                        expressGraph.setArgs(arg);
                        var node = that._CreateProfileGeomrtry(geoObj, expressGraph, L, H, D, element);
                        for (var j = 0; node && j < graphNum; ++j) {
                            var nodeCpy = node.clone();
                            graphparam.DJ == 1 ? nodeCpy.position.setX(j * L) : nodeCpy.position.setY(j * D);
                            rootNode.add(nodeCpy);
                        }
                    }
                }
            }
            else if (graphparam.PL == 2) {//"PlaneXZ"
                if (graphparam.BarH > 0 && graphparam.DJ != 0) {
                    if (graphparam.DJ == 1) {
                        graphparam.BarH = L / Math.round(L / graphparam.BarH);
                        graphNum = L / graphparam.BarH;
                        L = graphparam.BarH;
                    }
                    else if (graphparam.DJ == 2) {
                        graphparam.BarH = H / Math.round(H / graphparam.BarH);
                        graphNum = H / graphparam.BarH;
                        H = graphparam.BarH;
                    }
                }
                for (var i = 0; i < graphChildren.length; ++i) {
                    var element = graphChildren[i];
                    if (element.nodeName == "PlaneXZ") {
                        expressGraph.L = L;
                        arg["W"] = { "值": H };
                        expressGraph.setArgs(arg);
                        var node = that._CreateProfileGeomrtry(geoObj, expressGraph, L, H, D, element);
                        for (var j = 0; node && j < graphNum; ++j) {
                            var nodeCpy = node.clone();
                            graphparam.DJ == 1 ? nodeCpy.position.setX(j * L) : nodeCpy.position.setZ(j * H);
                            rootNode.add(nodeCpy);
                        }
                    }
                }
            }
            else if (graphparam.PL == 3) {//"PlaneYZ"
                if (graphparam.BarH > 0 && graphparam.DJ != 0) {
                    if (graphparam.DJ == 1) {
                        graphparam.BarH = D / Math.round(D / graphparam.BarH);
                        graphNum = D / graphparam.BarH;
                        D = graphparam.BarH;
                    }
                    else if (graphparam.DJ == 2) {
                        graphparam.BarH = H / Math.round(H / graphparam.BarH);
                        graphNum = H / graphparam.BarH;
                        H = graphparam.BarH;
                    }
                }
                for (var i = 0; i < graphChildren.length; ++i) {
                    var element = graphChildren[i];
                    if (element.nodeName == "PlaneYZ") {
                        expressGraph.L = D;
                        arg["W"] = { "值": H };
                        expressGraph.setArgs(arg);
                        var node = that._CreateProfileGeomrtry(geoObj, expressGraph, L, H, D, element);
                        for (var j = 0; node && j < graphNum; ++j) {
                            var nodeCpy = node.clone();
                            for (var k = 0; graphNum > 1 && k < nodeCpy.children.length; ++k) {
                                var uv = nodeCpy.children[k].geometry.attributes.uv.array;
                                for (var len = uv.length; len--;) {
                                    if (len % 2 == 0) {
                                        uv[len] += j * H;
                                    }
                                }
                            }
                            graphparam.DJ == 1 ? nodeCpy.position.setZ(j * H) : nodeCpy.position.setY(j * H);
                            rootNode.add(nodeCpy);
                        }
                    }
                }
            }
        }
        else {
            for (var i = 0; i < graphChildren.length; ++i) {
                var element = graphChildren[i];
                if (element.children.length == 0)
                    continue;
                if (element.nodeName == "PlaneXY") {
                    expressGraph.L = L;
                    arg["W"] = { "值": D };
                    expressGraph.setArgs(arg);
                }
                else if (element.nodeName == "PlaneYZ") {
                    expressGraph.L = D;
                    arg["W"] = { "值": H };
                    expressGraph.setArgs(arg);
                }
                else if (element.nodeName == "PlaneXZ") {
                    expressGraph.L = L;
                    arg["W"] = { "值": H };
                    expressGraph.setArgs(arg);
                }
                var profileNode = that._CreateProfileGeomrtry(geoObj, expressGraph, L, H, D, element);
                rootNode.add(profileNode);
            }
        }
        console.log(params)
        var angle = params['CA'] || 0;
        
        if (graphparam.JX == "3")//X旋转
            rootNode.rotateX(THREE.Math.degToRad(angle));
        else if (graphparam.JX == "4")//Y旋转
            rootNode.rotateY(THREE.Math.degToRad(angle));
             
        rootNode.children.length > 0 && success && success(rootNode);

        that.invalidateFun && that.invalidateFun(geoObj.MemData.guid);
    }, undefined, function (data) { that.ignoretexture && that.invalidateFun && that.invalidateFun(); }]);

    //return this._createBoxGeometry(geoObj, express, L, H, D, new THREE.LineBasicMaterial({ color: 0xff0000 }), true);
}

CClosetModelTool.prototype._CreateX3dRGeometryLst = function (geoObj, success) {
    var x3dUrl = geoObj["ThreedGraphic"];//this.funcGetX3d(geoObj["ThreedGraphic"]);
    x3dUrl = x3dUrl.replace(/\\/g, '\/');
    var baseurl = x3dUrl.substring(0, x3dUrl.lastIndexOf('\/') + 1);
    var that = this;
    this.ignoretexture && this.asynLoadedFile++;
    that.funcGetResourceData.apply(gMainApp, ['X3D', x3dUrl, function (content) {
        if (content[content.length - 2] = ',') {
            content = content.substring(0, content.length - 4);
            content += ']'
        }
        var lstfile = JSON.parse(content);
        var root = new THREE.Object3D;
        var size = geoObj.MemData.Size;
        for (var i = 0; i < lstfile.length; ++i) {
            var file3d = lstfile[i].FILENAME;
            var lmin = lstfile[i].LMIN;
            var lmax = lstfile[i].LMAX;
            var dmin = lstfile[i].DMIN;
            var dmax = lstfile[i].DMAX;
            var hmin = lstfile[i].HMIN;
            var hmax = lstfile[i].HMAX;
            if (size.L < lmin || size.L > lmax || size.D < dmin || size.D > dmax || size.H < hmin || size.H > hmax)
                continue;
            that._CreateX3dRGeometry(geoObj, baseurl + file3d, function (node) {
                root.add(node);
            })
        }
        success && success(root);

        that.invalidateFun && that.invalidateFun();
    }, undefined, function (data) { that.ignoretexture && that.invalidateFun && that.invalidateFun(); }]);
    //return this._createBoxGeometry(geoObj, express, L, H, D, new THREE.LineBasicMaterial({ color: 0xff0000 }), true);
}

CClosetModelTool.prototype._CreatePath3dGeometry = function (geoObj, path3dUrl, success) {
    var params = geoObj.MemData.Params || {};

    var that = this;
    this.ignoretexture && this.asynLoadedFile++;
    that.funcGetResourceData.apply(gMainApp, ['PATH3D', path3dUrl, function (responseText) {
        var rootNode = new THREE.Object3D;
        var size = geoObj.MemData.Size;
        var o = JSON.parse(responseText);
        for (var i = 0; i < o.length; ++i) {
            var object = o[i];

            //第一个参数放板的宽度，比如说512毫米。
            //第二个参数放板的高度，比如说512毫米。
            //第三个参数控制贴图的缩放程度。
            //第四个决定是否使用webGL方式生成凹凸贴图，true代表使用webGL方式。不填默认代表true。
            //第五个参数可以自己传递一个画布进去涂鸦，是可选参数。
            var bumpMap = new BumpMapMaker(size.L, size.H, 2, true);

            var pathKnife = [];
            var arg = {};
            for (var element in object.args) {
                if (params.hasOwnProperty(element) && params[element] != 0) {
                    arg[element] = { "值": params[element] };
                }
                else {
                    arg[element] = { "值": object.args[element] };
                }

                if (element == "L") {
                    arg[element] = arg[element]["值"];
                }
            }
            for (var item in params) {
                arg[item] = { "值": params[item] };
            }

            var expressGraph = new hg3dExpress(arg, 1);
            expressGraph.setArgs(arg);
            var path = object.path;
            for (var j = 0; j < path.length; ++j) {
                pathKnife.push(new knifePos(new THREE.Vector2(
                    expressGraph.compute(path[j].x),
                    expressGraph.compute(path[j].y)
                ), expressGraph.compute(path[j].z)));
            }

            var knifeShape = new KnifeShape([
                new THREE.Vector2(0, 30),
                new THREE.Vector2(30, 0)
            ]);

            //创建一条刀路。这个对象包括刀的走向和刀头的形状。-----------------
            var firstKnifePath = new KnifePath(pathKnife, knifeShape);

            //要画的线的粗细。单位是毫米-------------------------------------
            var myCanvas = bumpMap.Make([firstKnifePath]);

            var texture = new THREE.Texture(myCanvas);
            var textureLoader = new THREE.TextureLoader();
            var diffuseMap = textureLoader.load("http://qdsoft.huaguangsoft.com/htmloutput/3DViewer//js/wood.jpg", function () {
                that.invalidateFun()
            });

            //前面那个面的材质
            var frontMat = new THREE.MeshPhongMaterial({ map: diffuseMap, bumpMap: texture, bumpScale: 0.02 });
            var otherMat = new THREE.MeshPhongMaterial({ map: diffuseMap })
            //创建一个正方体做门板
            var gCube = new THREE.Mesh(new THREE.CubeGeometry(size.L, size.H, size.D),
                [
                    otherMat,
                    otherMat,
                    otherMat,
                    otherMat,
                    frontMat,
                    otherMat
                ]
            );
            ClosetUtil.Material.CollectMaterial(gCube);
            rootNode.add(gCube);
        }

        success && success(rootNode);

        that.invalidateFun && that.invalidateFun(geoObj.MemData.guid);
    }, undefined, function (data) { that.ignoretexture && that.invalidateFun && that.invalidateFun(); }]);
}

CClosetModelTool.prototype._CreateX3dRGeometry = function (geoObj, x3dUrl, success) {
    var preImg = geoObj.hasOwnProperty('Material') ? geoObj['Material']['Img'] : '';
    preImg = preImg || '';
    var that = this;
    var size = geoObj.MemData.Size;
    this.ignoretexture && this.asynLoadedFile++;
    that.funcGetResourceData.apply(gMainApp, ['X3D', x3dUrl, function (response) {
        var root = new THREE.Object3D;
        var fs = new Object();
        var obj = new Object();
        fs.buffer = response;
        fs.offset = 0;
        FileX3D.LoadFromX3D(fs, obj);

        var meshlist = obj.meshlist;
        if (!meshlist) {
            that.ignoretexture && that.invalidateFun && that.invalidateFun();
            return;
        }

        for (var i = 0; i < meshlist.length; ++i) {
            var vertextlist = meshlist[i].vertexlist;
            var facelist = meshlist[i].facegrouplist;
            var src = {
                vertices: [],
                normals: [],
                uvs: []
            };
            for (var j = 0, vertlen = vertextlist.length; j < vertlen; ++j) {
                src.vertices.push(vertextlist[j].v_0,
                    vertextlist[j].v_1,
                    vertextlist[j].v_2);

                src.normals.push(vertextlist[j].n_0,
                    vertextlist[j].n_1,
                    vertextlist[j].n_2);

                src.uvs.push(vertextlist[j].t_0,
                    vertextlist[j].t_1);
            }

            for (var j = 0, facelen = facelist.length; j < facelen; ++j) {
                var geometry = {
                    vertices: [],
                    normals: [],
                    colors: [],
                    uvs: []
                };

                var indexlist = facelist[j].indexlist;
                for (var k = 0, indexlen = indexlist.length; k < indexlen; ++k) {
                    var index = indexlist[k];
                    geometry.vertices.push(src.vertices[3 * index.vi + 0],
                        src.vertices[3 * index.vi + 1],
                        src.vertices[3 * index.vi + 2]);
                    geometry.normals.push(src.normals[3 * index.ni + 0],
                        src.normals[3 * index.ni + 1],
                        src.normals[3 * index.ni + 2]);
                    geometry.uvs.push(src.uvs[2 * index.ti + 0],
                        src.uvs[2 * index.ti + 1]);
                }

                if (geometry.vertices.length > 0) {
                    var buffergeometry = new THREE.BufferGeometry();
                    buffergeometry.setAttribute('position', new THREE.Float32BufferAttribute(geometry.vertices, 3));
                    if (geometry.normals.length > 0) {
                        buffergeometry.setAttribute('normal', new THREE.Float32BufferAttribute(geometry.normals, 3));
                    } else {
                        buffergeometry.computeVertexNormals();
                    }
                    if (geometry.uvs.length > 0) {
                        buffergeometry.setAttribute('uv', new THREE.Float32BufferAttribute(geometry.uvs, 2));
                    }

                    var m2tName = facelist[j].mMatName || "";
                    if (geoObj["Material"]["Label"] == facelist[j].mTextureDialog && facelist[j].mTextureDialog != "")
                        m2tName = preImg;
                    var material = that.matContainer[m2tName];
                    var mesh = new THREE.Mesh(buffergeometry, material);
                    ClosetUtil.Material.CollectMaterial(mesh);
                    mesh.add(that._CreateBorder(buffergeometry));
                    root.add(mesh);
                }
            }
        }

        var meshBB = new THREE.Box3();
        root.updateMatrixWorld(true);
        meshBB.setFromObject(root);

        var scaleX = size.L / (meshBB.getSize(new THREE.Vector3()).x);
        var scaleY = size.H / (meshBB.getSize(new THREE.Vector3()).y);
        var scaleZ = size.D / (meshBB.getSize(new THREE.Vector3()).z);
        root.scale.set(scaleX, scaleY, scaleZ);
        root.position.setX(-meshBB.min.x * scaleX);
        root.position.setY(-meshBB.min.y * scaleY);
        root.position.setZ(-meshBB.min.z * scaleZ);

        success && success(root);

        that.invalidateFun && that.invalidateFun(geoObj.MemData.guid);
    }, undefined, function (data) { that.ignoretexture && that.invalidateFun && that.invalidateFun(); }]);

    //return this._createBoxGeometry(geoObj, express, L, H, D, new THREE.LineBasicMaterial({ color: 0xff0000 }), true);
}

//根据截面生成图形，express L H D 是计算出来的，需要处理内部的参数
CClosetModelTool.prototype._CreateProfileGeomrtry = function (geoObj, express, L, H, D, element) {
    console.log(geoObj);
    if (!L || !H || !D)
        return;

    var materialObj = geoObj["Material"] || {};
    var that = this;
    var material = that.mt2MatGL[that._GetMatKey(materialObj)];
    var matWidth = material.userData.width || 1220;
    var matHeigh = material.userData.height || 2440;
    var matMode = material.userData.matMode || 0;

    var graphparam = geoObj.GraphParam || {};
     console.log(graphparam);
    var ptsProfile = [];
    var ptsType = [];
    var length, width;
    if (element != undefined) {
        ptsProfile = that._GetProfileFromX2d(element, express, ptsType);
    }
    else if (graphparam.hasOwnProperty('PL') && graphparam.PL != '0') {
        graphparam.PL == 1 && (length = L, width = D);//PlaneXY
        graphparam.PL == 2 && (length = L, width = H);//PlaneXZ
        graphparam.PL == 3 && (length = D, width = H);//PlaneYZ

        ptsProfile.push(new THREE.Vector2(0, 0));
        ptsProfile.push(new THREE.Vector2(length, 0));
        ptsProfile.push(new THREE.Vector2(length, width));
        ptsProfile.push(new THREE.Vector2(0, width));
    }

    if (ptsProfile.length == 0) {
        return that._CreateBoxGeometry(geoObj, material, false);
    }
    function checkShun(pts) {
        let area = 0;
        for (var i = 0; i < pts.length; i++) {
            let j = (i + 1) % pts.length;
            area += pts[i].x * pts[j].y;
            area -= pts[j].x * pts[i].y;
        }
        if (area > 0) {
            return false;
        } else {
            return true;
        }
    }
    //if (checkShun(ptsProfile)) {
    //   ptsProfile = ptsProfile.reverse();
    // }
    console.log(graphparam.PL)
    var height;
    element = element || {};

    (graphparam.PL == "1" || element.nodeName == "PlaneXY") && (height = H, length = L, width = D);
    (graphparam.PL == "2" || element.nodeName == "PlaneXZ") && (height = -D, length = L, width = H);
    (graphparam.PL == "3" || element.nodeName == "PlaneYZ") && (height = L, length = D, width = H);
    if (height === undefined)
        return;

    if (matMode == 3) {
        matWidth = width;
        matHeigh = length;
    }
    var profileBottom = [], profileTop = [], profileUV = [];
    var count = ptsProfile.length;
    var profileBB = new THREE.Box3;
    for (var i = 0; i < count; ++i) {
        graphparam.JX == 1 && (ptsProfile[i].x = length - ptsProfile[i].x);
        graphparam.JX == 2 && (ptsProfile[i].y = width - ptsProfile[i].y);
    }
    var DI = (geoObj.Size && geoObj.Size.DI) || 1;
    var di = (DI == 1 || DI == 2 || DI == 6) ? 1 : 0;
    for (var i = 0; i < count; ++i) {
        profileBottom.push(new THREE.Vector3(ptsProfile[i].x, ptsProfile[i].y, 0));
        profileTop.push(new THREE.Vector3(ptsProfile[i].x, ptsProfile[i].y, -height));
        if (di == 1)
            profileUV.push(new THREE.Vector2(-ptsProfile[i].y / matHeigh, ptsProfile[i].x / matWidth));
        else
            profileUV.push(new THREE.Vector2(ptsProfile[i].x / matWidth, ptsProfile[i].y / matHeigh));
        profileBB.expandByPoint(profileBottom[i]);
    }
    var profileSize = profileBB.getSize(new THREE.Vector3());

    if (graphparam.Cut == 1 || graphparam.Cut == 2) {
        var cutA = graphparam.CutA;
        var cutB = graphparam.CutB;
        if (cutA != 0) {
            var normal= new THREE.Vector3(0, 0, 1);;
            if(graphparam.PL=="2"){
                normal= new THREE.Vector3(1, 0, 0);
            }else if(graphparam.PL=="3"){
                normal= new THREE.Vector3(0, 0, 1);
            }
             
            if (graphparam.Cut == 1) {//X轴切割
                normal.applyAxisAngle(new THREE.Vector3(1, 0, 0), THREE.Math.degToRad(cutA));
                for (var i = 0; i < count; ++i) {
                    var target = that._ProjectPtonPlane(new THREE.Vector3(cutA < 0 ? profileSize.x : 0, cutA > 0 ? profileSize.y : 0, 0), normal, profileBottom[i]);
                    profileBottom[i].set(target.x, target.y, target.z);
                }
            }
            else if (graphparam.Cut == 2) {//Y轴切割
                normal.applyAxisAngle(new THREE.Vector3(0, -1, 0), THREE.Math.degToRad(cutA));
                for (var i = 0; i < count; ++i) {
                    var target = that._ProjectPtonPlane(new THREE.Vector3(cutA > 0 ? profileSize.x : 0, cutA < 0 ? profileSize.y : 0, 0), normal, profileBottom[i]);
                    profileBottom[i].set(target.x, target.y, target.z);
                }
            }
        }
        if (cutB != 0) {
            var normal= new THREE.Vector3(0, 0, 1);
            if(graphparam.PL=="2"){
                normal= new THREE.Vector3(1, 0, 0);
               
            }else if(graphparam.PL=="3"){
                normal= new THREE.Vector3(0, 0, 1);
            }
            if (graphparam.Cut == 1) {//X轴切割
                normal.applyAxisAngle(new THREE.Vector3(-1, 0, 0), THREE.Math.degToRad(cutB));
                for (var i = 0; i < count; ++i) {
                    var target = that._ProjectPtonPlane(new THREE.Vector3(cutB < 0 ? profileSize.x : 0, cutB > 0 ? profileSize.y : 0, -height), normal, profileTop[i]);
                    profileTop[i].set(target.x, target.y, target.z);
                }
            }
            else if (graphparam.Cut == 2) {//Y轴切割
                normal.applyAxisAngle(new THREE.Vector3(0, 1, 0), THREE.Math.degToRad(cutB));
                for (var i = 0; i < count; ++i) {
                    var target = that._ProjectPtonPlane(new THREE.Vector3(cutB > 0 ? profileSize.x : 0, cutB < 0 ? profileSize.x : 0, -height), normal, profileTop[i]);
                    profileTop[i].set(target.x, target.y, target.z);
                }
            }
        }
    }

    var vertices = [];
    var uvs = [];
    for (var i = 0; i < count; ++i) {
        var next = i == count - 1 ? 0 : i + 1;
        vertices.push.apply(vertices, profileBottom[i].toArray());
        vertices.push.apply(vertices, profileBottom[next].toArray());
        vertices.push.apply(vertices, profileTop[i].toArray());

        var mat = new THREE.Matrix4().identity();
        mat.makeTranslation(-profileBottom[i].x, -profileBottom[i].y, -profileBottom[i].z);
        mat = mat.multiply(new THREE.Matrix4().makeRotationAxis(profileBottom[next].clone().sub(profileBottom[i]), -Math.PI * 0.5));
        mat = mat.multiply(new THREE.Matrix4().makeTranslation(profileBottom[i].x, profileBottom[i].y, profileBottom[i].z));
        var rotateI = profileTop[i].clone().applyMatrix4(mat);
        var rotateNext = profileTop[next].clone().applyMatrix4(mat);

        uvs.push.apply(uvs, profileUV[i].toArray());
        if (di == 1)
            uvs.push.apply(uvs, new THREE.Vector2(-rotateI.y / matHeigh, rotateI.x / matWidth).toArray());
        else
            uvs.push.apply(uvs, new THREE.Vector2(rotateI.x / matWidth, rotateI.y / matHeigh).toArray());
        uvs.push.apply(uvs, profileUV[i].toArray());

        vertices.push.apply(vertices, profileTop[i].toArray());
        vertices.push.apply(vertices, profileBottom[next].toArray());
        vertices.push.apply(vertices, profileTop[next].toArray());

        if (di == 1)
            uvs.push.apply(uvs, new THREE.Vector2(-rotateI.y / matHeigh, rotateI.x / matWidth).toArray());
        else
            uvs.push.apply(uvs, new THREE.Vector2(rotateI.x / matWidth, rotateI.y / matHeigh).toArray());
        uvs.push.apply(uvs, profileUV[next].toArray());
        if (di == 1)
            uvs.push.apply(uvs, new THREE.Vector2(-rotateNext.y / matHeigh, rotateNext.x / matWidth).toArray());
        else
            uvs.push.apply(uvs, new THREE.Vector2(rotateNext.x / matWidth, rotateNext.y / matHeigh).toArray());
    }

    var node = new THREE.Object3D;

    var buffergeometry = new THREE.BufferGeometry();
    buffergeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    buffergeometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));
    buffergeometry.computeVertexNormals();
    node.add(new THREE.Mesh(buffergeometry, material));
    node.add(that._CreateBorder(buffergeometry));
    ClosetUtil.Material.CollectMaterial(node);

    var allData = [];
    for (var i = 0; i < count; ++i) {
        allData.push(profileBottom[i].x);
        allData.push(profileBottom[i].y);
        allData.push(profileBottom[i].z);
    }
    var triangleBottom = earcut(allData, undefined, 3);
    var meshIndex = [];
    for (var i = 0; i < triangleBottom.length; i++) {
        meshIndex.push(triangleBottom[i]);
    }

    var uvarray = [];
    for (var i = 0; i < count; ++i) {
        uvarray.push.apply(uvarray, profileUV[i].toArray());
    }
    var geoBottom = new THREE.BufferGeometry().setFromPoints(profileBottom);
    geoBottom.setAttribute('uv', new THREE.Float32BufferAttribute(uvarray, 2));
    geoBottom.setIndex(meshIndex);
    geoBottom.computeVertexNormals();
    var meshBottom = new THREE.Mesh(geoBottom, material);
    ClosetUtil.Material.CollectMaterial(meshBottom);
    node.add(meshBottom);
    node.add(that._CreateBorder(geoBottom));

    var geoTop = new THREE.BufferGeometry().setFromPoints(profileTop);
    geoTop.setAttribute('uv', new THREE.Float32BufferAttribute(uvarray, 2));
    geoTop.setIndex(meshIndex);
    geoTop.computeVertexNormals();
    var meshTop = new THREE.Mesh(geoTop, material);
    ClosetUtil.Material.CollectMaterial(meshTop);
    node.add(meshTop);
    node.add(that._CreateBorder(geoTop));

    var mat = new THREE.Matrix4().identity();
    if (graphparam.PL == 1 || element.nodeName == "PlaneXY") {//PlaneXY
        node.rotateX(Math.PI / 2);
        mat = mat.premultiply(new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), Math.PI * 0.5));
    }
    else if (graphparam.PL == 3 || element.nodeName == "PlaneYZ") {//"PlaneYZ"
        node.rotateY(-Math.PI / 2);
        mat = mat.premultiply(new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), -Math.PI * 0.5));
    }else if(graphparam.PL == "4"){
        console.log("4"==4)
    }

    //将数据保存到MemData中供2D使用
    var ptLen = profileTop.length;
    var tempTop = [], tempBottom = [];
    for (var n = 0; n < ptLen; ++n) {
        tempTop.push(profileTop[n].clone().applyMatrix4(mat));
        tempBottom.push(profileBottom[n].clone().applyMatrix4(mat));
    }

    geoObj.MemData.Profile = geoObj.MemData.Profile || {};
    geoObj.MemData.Profile.TopData = tempTop;
    geoObj.MemData.Profile.BottomData = tempBottom;
    if (ptsType.length > 0)
        geoObj.MemData.Profile.PtsType = ptsType;

    return node;
}

CClosetModelTool.prototype._GetProfileFromX2d = function (element, express, ptType) {
    var elementChildren = element.children;
    var pts = [];
    for (var i = 0; i < elementChildren.length; ++i) {
        var point = elementChildren[i];
        if (point.nodeName == "Point") {
            pts.push(new THREE.Vector2(express.compute(point.attributes.X.nodeValue),
                express.compute(point.attributes.Y.nodeValue)
            ));
            ptType.push(0);
        }
        else if (point.nodeName == "Arc") {
            var pt = {};
            pt.x = express.compute(point.attributes.X.nodeValue),
                pt.y = express.compute(point.attributes.Y.nodeValue),
                pt.r = express.compute(point.attributes.R.nodeValue),
                pt.s_angle = express.compute(point.attributes.StartAngle.nodeValue);
            pt.angle = express.compute(point.attributes.Angle.nodeValue);

            var angle0 = THREE.Math.degToRad(pt.s_angle);
            var angle = 2.0 * Math.PI / 120.0;
            angle = pt.angle < 0 ? -angle : angle;
            var x1 = pt.x - Math.cos(angle0) * pt.r;
            var y1 = pt.y + Math.sin(angle0) * pt.r;
            var n = Math.abs(pt.angle) / 3;
            for (var j = 0; j < n; j++) {
                pts.push(new THREE.Vector2(x1 + pt.r * Math.cos(angle * j + angle0),
                    (y1 - pt.r * Math.sin(angle * j + angle0))
                ));
                ptType.push(1);
            }
        }
    }

    return pts;
}

CClosetModelTool.prototype._CreateBoxGeometry = function (geoObj, material, hide) {
    var L = geoObj.MemData.Size.L;
    var D = geoObj.MemData.Size.D;
    var H = geoObj.MemData.Size.H;
    if (geoObj.hasOwnProperty('Product')) {
        geoObj = geoObj["Product"];
    }
    material.userData = material.userData || {};
    var matWidth = material.userData.width || 2440;
    var matHeigh = material.userData.height || 1220;
    var matMode = material.userData.matMode || 0;

    //底面和顶面，最后需饶X轴旋转90度,并设置y值分别为0和H
    var ptsBottom = [];
    ptsBottom.push(new THREE.Vector2(0, 0));
    ptsBottom.push(new THREE.Vector2(L, 0));
    ptsBottom.push(new THREE.Vector2(L, D));
    ptsBottom.push(new THREE.Vector2(0, D));

    //左面和右面,最后需绕Y轴旋转90度，并设置x值分别为0和L
    var ptsLeft = [];
    ptsLeft.push(new THREE.Vector2(0, 0));
    ptsLeft.push(new THREE.Vector2(D, 0));
    ptsLeft.push(new THREE.Vector2(D, H));
    ptsLeft.push(new THREE.Vector2(0, H));

    //前面和后面,最后设置z值分别为0和D
    var ptsFront = [];
    ptsFront.push(new THREE.Vector2(0, 0));
    ptsFront.push(new THREE.Vector2(L, 0));
    ptsFront.push(new THREE.Vector2(L, H));
    ptsFront.push(new THREE.Vector2(0, H));

    var DI = (geoObj.Size && geoObj.Size.DI) || 1;
    var di = 1;
    var textureFace = 1;//1,上下；2,左右面；3,前后面
    DI == 1 && (textureFace = 1, di = 1);
    DI == 5 && (textureFace = 1, di = 0);
    DI == 4 && (textureFace = 2, di = 0);
    DI == 6 && (textureFace = 2, di = 1);
    DI == 2 && (textureFace = 3, di = 1);
    DI == 3 && (textureFace = 3, di = 0);

    var node = new THREE.Object3D;
    node.visible = hide ? false : true;
    //底面和顶面
    for (var i = 0; i < 2; ++i) {
        var s = new THREE.Shape(ptsBottom);
        var geo = new THREE.ShapeGeometry(s);
        if (geo.faces.length <= 0)
            continue;
        !hide && geo.computeVertexNormals();
        !hide && this._ResizeGeometryUV(geo, matMode == 3 ? L : matHeigh, matMode == 3 ? D : matWidth, 'BT', di);

        var mesh = new THREE.Mesh(geo, material);
        ClosetUtil.Material.CollectMaterial(mesh);
        mesh.rotateX(Math.PI / 2);
        mesh.position.y = (i == 0) ? 0 : H;
        !hide && mesh.add(this._CreateBorder(geo));
        //mesh.visible = hide ? false : true;
        node.add(mesh);
    }
    //左面和右面
    for (var i = 0; i < 2; ++i) {
        var s = new THREE.Shape(ptsLeft);
        var geo = new THREE.ShapeGeometry(s);
        if (geo.faces.length <= 0)
            continue;
        !hide && geo.computeVertexNormals();
        !hide && this._ResizeGeometryUV(geo, matMode == 3 ? D : matHeigh, matMode == 3 ? H : matWidth, 'LR', di);

        var mesh = new THREE.Mesh(geo, material);
        ClosetUtil.Material.CollectMaterial(mesh);
        mesh.rotateY(-Math.PI / 2);
        mesh.position.x = (i == 0) ? 0 : L;
        !hide && mesh.add(this._CreateBorder(geo));
        //mesh.visible = hide ? false : true;
        node.add(mesh);
    }
    //前面和后面
    for (var i = 0; i < 2; ++i) {
        var s = new THREE.Shape(ptsFront);
        var geo = new THREE.ShapeGeometry(s);
        if (geo.faces.length <= 0)
            continue;
        !hide && geo.computeVertexNormals();
        !hide && this._ResizeGeometryUV(geo, matMode == 3 ? L : matHeigh, matMode == 3 ? H : matWidth, 'FB', di);

        var mesh = new THREE.Mesh(geo, material);
        ClosetUtil.Material.CollectMaterial(mesh);
        mesh.position.z = (i == 0) ? 0 : D;
        !hide && mesh.add(this._CreateBorder(geo));
        //mesh.visible = hide ? false : true;
        node.add(mesh);
    }

    if (geoObj.hasOwnProperty('GraphParam')) {
        var rotateDir = geoObj['GraphParam']['JX'];
        var angle = geoObj.MemData.Params['CA'] || 0;
        if (angle != 0) {
            if (rotateDir == 3)//X旋转
                node.rotateX(THREE.Math.degToRad(angle));
            else if (rotateDir == 4)//Y旋转
                node.rotateZ(THREE.Math.degToRad(angle));
        }
    }

    return node;
}

CClosetModelTool.prototype._CreateBorder = function (geometry) {
    var edges = new THREE.EdgesGeometry(geometry, 9.0);

    var vertexPositions = edges.attributes.position.array;

    var lineGeometry = new THREE.LineSegmentsGeometry();
    lineGeometry.setPositions(vertexPositions);

    var matLine = new THREE.LineMaterial({
        linewidth: 0.002,
        color: 0x000000
    });

    var edgeLine = new THREE.Line2(lineGeometry, matLine);
    edgeLine.renderOrder = 999;
    //edgeLine.onBeforeRender = function(render){render.clearDepth();}
    edgeLine.visible = true;

    return edgeLine;
}

CClosetModelTool.prototype._ResizeGeometryUV = function (geo, length, width, face, DI) {
    geo.faceVertexUvs[0].forEach(function (a) {
        a.forEach(function (a) {
            if (DI == 1) {
                var temp = a.x;
                a.x = -a.y;
                a.y = temp;
                a.x /= length;
                a.y /= width;
            }
            else {
                a.x /= length;
                a.y /= width;
            }
        })
    })
}

CClosetModelTool.prototype._GetMaterial = function (matInfo, callback) {
    var that = this;
    var matKey = this._GetMatKey(matInfo);
    if (this.ignoretexture == true) {
        that.mt2MatGL = that.mt2MatGL || {};
        that.mt2MatGL[matKey] = this.whiteBlackMat;
        return;
    }

    if (that.mt2MatGL && that.mt2MatGL.hasOwnProperty(matKey)) {
        callback && callback(that.mt2MatGL[matKey])
    }
    else {
        var material = new THREE.MeshPhongMaterial();
        material.side = THREE.DoubleSide;
        material.roughness = 0;
        material.userData = material.userData || {};
        material.userData.name = matKey;
        that.mt2MatGL = that.mt2MatGL || {};
        that.mt2MatGL[matKey] = material;

        var matUlr = 'http://qdsoft.huaguangsoft.com/BlockGrph/MAT_GetItemsByLabelAndType/?';
        matUlr = matUlr + 'qdsoftid=' + gMainApp.mQdSoftid;
        if (matInfo.Label && matInfo.Label.length > 0)
            matUlr = matUlr + '&classlabel=' + matInfo.Label;
        else
            matUlr += '&classlabel=板材';

        if (matInfo.Mat && matInfo.Mat.length > 0)
            matUlr = matUlr + '&matpatern=' + matInfo.Mat;
        else
            matUlr += '&matpatern=尊爵实木颗粒板';

        if (matInfo.Name && matInfo.Name.length > 0)
            matUlr = matUlr + '&sName=' + matInfo.Name;
        else
            matUlr += '&sName=优享';

        if (matUlr.indexOf('&classlabel=') == -1 || matUlr.indexOf('&matpatern=') == -1) {
            callback && callback(material);
        }
        else {
            that.funcGetResourceData.apply(gMainApp, ['MT2', matUlr, function (responseText) {
                var o = JSON.parse(responseText);
                if (o.datalist && o.datalist.length > 0) {
                    var data = o.datalist[0];
                    if (data.data) {
                        var attr = JSON.parse(data.data);
                        for (var key in attr) {
                            var val = attr[key];
                            if ('color' == key) {
                                //material.color.setHex(Number.parseInt(val, 16));
                            }
                            else if ('specular' == key) {
                                //material.specular.setHex(Number.parseInt(val, 16));
                            }
                            else if ('emissive' == key) {
                                //material.emissive.setHex(Number.parseInt(val, 16));
                            }
                            else if ('shininess' == key) {
                                material.shininess = val;
                            }
                            else if ('transparent' == key) {
                                material.transparent = val;
                            }
                            else if ('opacity' == key) {
                                material.opacity = val;
                            }
                        }
                    }
                    var imgUrl = '';
                    if (data.image) {
                        var s = data.image.split('.');
                        var imgUrl = 'http://qdsoft.huaguangsoft.com/BlockGrph/FP_GetImage/?';
                        if (s.length == 2) {
                            imgUrl = imgUrl + 'path=' + s[0];
                            imgUrl = imgUrl + '&type=' + s[1];
                            imgUrl = imgUrl + '&size=L';
                        }
                        else {
                            imgUrl = imgUrl + 'path=' + data.img;
                            imgUrl = imgUrl + '&type=png';
                            imgUrl = imgUrl + '&size=L';
                        }
                        imgUrl = imgUrl.replace(/\\/g, '\/');
                    }
                    else {
                        imgUrl = 'http://qdsoft.huaguangsoft.com/htmloutput/3DViewer/res/NoTexture.png';
                    }
                    var loader = new THREE.TextureLoader();
                    var texture = loader.load(imgUrl, function () {
                        that.invalidateFun();
                    });
                    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
                    material.map = texture;
                }
                material.needsUpdate = true;
                callback && callback(material);
            }, 'POST', function () {
                callback && callback(material);
            }]);
        }
    }
}

CClosetModelTool.prototype._ProjectPtonPlane = function (point, normal, p) {
    var plane = new THREE.Plane();
    plane.setFromNormalAndCoplanarPoint(normal.normalize(), point);
    var target = new THREE.Vector3();
    var line = new THREE.Line3(p, new THREE.Vector3(p.x, p.y, p.z - 1));
    var direction = line.delta(target);
    var denominator = plane.normal.dot(direction);
    if (denominator === 0) {
        // line is coplanar, return origin
        if (this.distanceToPoint(line.start) === 0) {
            return target.copy(line.start);
        }
        // Unsure if this is the correct method to handle this case.
        return undefined;
    }

    var t = - (line.start.dot(plane.normal) + plane.constant) / denominator;

    return target.copy(direction).multiplyScalar(t).add(line.start);
}

CClosetModelTool.prototype._GetMatKey = function (material) {
    if (!material) return "";
    var label = material['Label'] || "";
    var img = material['Mat'] || "";
    var name = material['Name'] || "";
    if (label.length == 0 || label == 'None') {
        material['Label'] = '板材';
        label = '板材';
    }
    if (img.length == 0 || img == 'None') {
        material['Mat'] = '尊爵实木颗粒板';
        img = '尊爵实木颗粒板';
    }
    if (name.length == 0 || name == 'None') {
        material['Name'] = '优享';
        name = '优享';
    }

    return label + '_' + img + '_' + name;
}

CClosetModelTool.prototype._UpdatePickAssistBox = function () {

}

CClosetModelTool.prototype._CreateLabelObj = function (blockObj, parent) {
    if (!blockObj.hasOwnProperty('Bind') || !parent)
        return;

    var parentBlock = gMainApp.GetBlockByGuid(parent.userData.hgCloset.guid);
    var bind = blockObj.Bind;
    var viewType = blockObj.ViewType;
    var data = bind.split('=');
    if (data.length != 2)
        return;

    var key = data[0];
    var val = data[1];
    if (blockObj.MemData.Size.hasOwnProperty(val))
        val = blockObj.MemData.Size[val];
    else if (blockObj.MemData.Arguments.hasOwnProperty(key))
        val = blockObj.MemData.Arguments[key];
    if (val == 0)
        return;

    var guid = blockObj.MemData.guid;

    var node = new THREE.Object3D;
    if (gMainApp != undefined && gMainApp.labelVisible != undefined) {
        node.visible = gMainApp.labelVisible;
    }
    node.userData.hgCloset = {};
    node.userData.hgCloset.labelNode = guid;

    var size = blockObj.MemData.Size;
    var pos = blockObj.MemData.Pos;
    var startPos, endPos;
    var txtPos = new THREE.Vector3();
    var midPos = new THREE.Vector3(pos.X, pos.Y, pos.Z);
    var L = size.L, D = size.D, H = size.H;
    if (data[1] == 'L') {
        txtPos.x += L / 2;
        startPos = new THREE.Vector3(0, 0, 0);
        endPos = new THREE.Vector3(L, 0, 0);
    }
    else if (data[1] == 'D') {
        txtPos.z += D / 2;
        startPos = new THREE.Vector3(0, 0, 0);
        endPos = new THREE.Vector3(0, 0, D);
    }
    else if (data[1] == 'H') {
        txtPos.y += H / 2;
        startPos = new THREE.Vector3(0, 0, 0);
        endPos = new THREE.Vector3(0, H, 0);
    }

    if (!startPos)
        return;

    var matLine = new THREE.LineMaterial({
        linewidth: 0.002,
        color: 0x999999
    });

    var vertexPositions0 = [];
    vertexPositions0.push.apply(vertexPositions0, startPos.toArray());
    vertexPositions0.push.apply(vertexPositions0, endPos.toArray());
    var lineGeometry0 = new THREE.LineSegmentsGeometry();
    lineGeometry0.setPositions(vertexPositions0);
    var edgeLine0 = new THREE.Line2(lineGeometry0, matLine);
    edgeLine0.renderOrder = 999;

    var lableCtx = document.createElement('canvas');
    lableCtx.height = 64;
    lableCtx.width = 128;
    var n = lableCtx.getContext('2d');
    n.clearRect(0, 0, 128, 64);
    n.font = "48px Arial";
    n.textAlign = 'center';
    n.textBaseline = 'middle';
    n.strokeStyle = '#fff';
    n.linewidth = 2;
    n.strokeText(val, lableCtx.width / 2, lableCtx.height / 2);
    n.fillStyle = '#000';
    n.fillText(val, lableCtx.width / 2, lableCtx.height / 2);
    n.restore();
    var labelMesh = new THREE.Mesh(new THREE.PlaneGeometry(144, 72, 0), new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide,
        visible: true,
        transparent: true,
        opacity: 0.9,
        map: new THREE.CanvasTexture(lableCtx)
    }));
    labelMesh.position.set(txtPos.x, txtPos.y, txtPos.z);

    edgeLine0.userData.hgCloset = {};
    edgeLine0.userData.hgCloset.labelNode = guid;
    labelMesh.userData.hgCloset = {};
    labelMesh.userData.hgCloset.labelNode = guid;
    labelMesh.userData.hgCloset.labelVal = val;
    node.add(edgeLine0);
    node.add(labelMesh);

    node.position.set(midPos.x, midPos.y, midPos.z);

    parent.add(node);
}